from django_simpleaggregation.models import Aggregate
from django_simpleaggregation.utils import smart_getattr
from django.contrib.contenttypes.models import ContentType

__all__ = ('AggregateAccessor', 'get_aggregate')

def get_aggregate(model, unique_field):
    content_type = ContentType.objects.get_for_model(model.__class__)
    get_kwargs = {
        'content_type' : content_type,
        'unique_field' : unique_field,
        'unique_field_data' : smart_getattr(model, unique_field)
    }
    agg = Aggregate.objects.get(**get_kwargs)
    return agg

class AggregateAccessor(object):
    def __init__(self, model_class, unique_field, direction = 'descending', 
        stop_before = 0, unique = True, paginate_by = None, page = None):
        self.model_class = model_class
        self.unique_field = unique_field
        self.direction = direction
        self.stop_before = stop_before
        self.unique = unique
        self.paginate_by = paginate_by
        self.page = page
        self.has_next = False
        self.has_previous = False
        self.is_paginated = False
        self._initialize_queryset()

    def _initialize_queryset(self):
        content_type = ContentType.objects.get_for_model(self.model_class)
        self.aggs = Aggregate.objects.filter(
            content_type = content_type,
            unique_field = self.unique_field
        )
        if self.page != None and self.paginate_by != None:
            self.limit = self.paginate_by
            self.offset = self.page * self.paginate_by
            self.is_paginated = True
        else:
            self.limit = self.aggs.count()
            self.offset = 0
            self.is_paginated = False
        if self.aggs[self.offset+self.limit:].count() > 0:
            self.has_next = True
        if self.offset < self.limit:
            self.has_previous = False
        else:
            self.has_previous = True

    def get_pagination_dict(self):
        to_return = {
            'has_next' : self.has_next,
            'has_previous' : self.has_previous,
            'next' : self.page + 1,
            'previous' : self.page - 1,
            'is_paginated' : self.is_paginated,
        }
        return to_return

    def has_next(self):
        return self.has_next
    
    def has_previous(self):
        return self.has_previous

    def get_list_by_count(self):
        return self._get_list('count')

    def get_list_by_user_defined(self):
        return self._get_list('user_defined')

    def _get_list(self, by):
        if self.direction == 'descending':
            self.aggs = self.aggs.order_by('-%s' % by)
        elif self.direction == 'ascending':
            self.aggs = self.aggs.order_by(by)
        current = []
        for agg in self.aggs[self.offset:self.offset+self.limit]:
            # The reason for the replacement is so that the query 'follows' the
            # user's unique data through several tables, if need be.
            kwargs = { self.unique_field.replace('.', '__') : agg.unique_field_data }
            filtered = self.model_class.objects.filter(**kwargs)
            # If it's unique, just return one object
            if self.unique:
                item = filtered[0]
                yield smart_getattr(item, self.unique_field, self.stop_before)
            # Otherwise, return a list of objects which this aggregate could
            # refer to.
            else:
                to_return = []
                for item in filtered:
                    obj = smart_getattr(item, self.unique_field, self.stop_before)
                    if obj not in to_return:
                        to_return.append(obj)
                yield to_return